demo article in English: stack overview and redesigned architecture diagrams

This commit is contained in:
2026-09-11 13:58:49 +02:00
parent 43e2bb4061
commit 9ca89f3e40
13 changed files with 573 additions and 524 deletions
-175
View File
@@ -1,175 +0,0 @@
---
title: "Jak działa to demo: portal statyczny + CMS oparty o git"
description: "Architektura rozwiązania, przydatne linki i porównanie klas rozwiązań: strona w 100% statyczna z graficznym edytorem treści vs CMS z własną bazą danych."
date: 2026-07-23
category: demo
author: Cyfronet
cover: /uploads/diagrams/cover-git-cms.svg
lang: pl
draft: false
---
Ten portal to **statyczne pliki HTML** generowane z plików Markdown trzymanych
w repozytorium git. Redaktor dostaje **graficzny edytor w przeglądarce** —
a mimo to **po stronie publicznej** nie działa żadna aplikacja ani baza:
między czytelnikiem a treścią jest wyłącznie serwer plików. Jedyny działający
serwis (Gitea) obsługuje edycję i stoi poza ścieżką czytelnika — wracamy do
tego uczciwie niżej. Ten artykuł został napisany i opublikowany dokładnie tą
ścieżką.
## Od zapisu do publikacji
![Pięć kroków publikacji: zapis w edytorze → commit w repo → detekcja zmiany → build strony → publikacja](/uploads/diagrams/od-zapisu-do-publikacji.svg)
Publikacja jest automatyczna — zapis w edytorze po chwili sam pojawia się
na stronie, bez żadnego ręcznego deployu. Każda zmiana to commit, więc
**pełna historia treści i możliwość cofnięcia są w gicie za darmo**.
## Jak to wygląda na maszynie
![Architektura na maszynie demo: redaktor zapisuje przez Sveltię do Gitei, timer systemd uruchamia jednorazowy kontener builda Astro, wynik trafia do wolumenu releases, a nginx serwuje czytelnikom wyłącznie statyczne pliki](/uploads/diagrams/architektura-maszyna.svg)
Dla porównania — ta sama maszyna z klasycznym CMS-em. Układ diagramu jest
celowo identyczny, żeby różnice było widać na pierwszy rzut oka: tu każdy
element działa bez przerwy, a panel logowania i aplikacja są wystawione
do internetu.
![Architektura klasycznego CMS z bazą danych: aplikacja z publicznym panelem admina i renderowaniem na żądanie działa non stop, obok baza danych wymagająca backupów i wolumen mediów](/uploads/diagrams/architektura-cms-z-baza.svg)
## Gdzie co jest
| Co | Gdzie |
|---|---|
| Portal | strona główna tego serwisu |
| Edytor treści | `/admin/` (link „Content editor" w stopce) |
| Gitea (repo `ctao/portal`) | port 3000 na maszynie demo |
| Konto demo | użytkownik `ctao` (hasło u prowadzącego demo) |
| Dokumentacja wdrożenia | katalog `deploy/` w repo kodu: `README.md` (runbook) |
Całość działa w podmanie na jednej maszynie: kontener Gitei, kontener nginx
i jednorazowy kontener builda odpalany przez systemd timer.
## Dlaczego strona statyczna
![Porównanie powierzchni ataku: CMS z bazą wystawia publicznie aplikację, panel logowania, bazę i pluginy — tu publiczne są tylko pliki HTML, a edycja idzie przez git dla zalogowanych](/uploads/diagrams/powierzchnia-ataku.svg)
- **Bezpieczeństwo**: publicznie wystawione są tylko pliki. Nie istnieje
panel admina dostępny z internetu, baza do wykradzenia ani runtime z CVE.
- **Utrzymanie**: nie ma aplikacji, która musi być monitorowana i
aktualizowana pod presją łatek bezpieczeństwa. Do utrzymania zostaje git
(który i tak utrzymujemy) i krótki skrypt builda.
- **Szybkość**: statyczny HTML to najszybsza możliwa strona — istotne też
dla SEO.
- **Historia**: wersjonowanie treści to naturalna cecha gita, nie płatna
funkcja produktu.
## Dwie klasy rozwiązań
Linia podziału jest często mylona: nie chodzi o to, czy treść leży w bazie
czy w plikach, tylko o to, **czy między czytelnikiem a treścią stoi
działająca aplikacja**.
| | Statyczne + git-CMS *(to demo)* | CMS serwujący stronę aplikacją |
|---|---|---|
| Przykłady | Sveltia, Decap (+ Astro / Hugo / Eleventy) | Strapi, WordPress, Drupal, Grav, TinaCMS |
| Treść żyje w | plikach Markdown w gicie | zwykle w bazie; Grav — w plikach, Tina — w gicie |
| W produkcji działa | serwer plików | aplikacja (zwykle + baza), non stop |
| Utrzymanie | skrypt builda + serwis gitowy | patche, aktualizacje, backupy bazy |
| Historia zmian | git, wbudowana | zależnie od produktu (bywa płatna) |
Dwa doprecyzowania, żeby tabela nie upraszczała: **Grav** trzyma treść
w plikach bez żadnej bazy — ale stronę i tak serwuje aplikacja PHP, więc pod
względem powierzchni ataku i utrzymania należy do prawej kolumny. **TinaCMS**
trzyma treść wręcz w Markdownie w gicie, ale do działania edytora wymaga
stale działającego backendu z bazą — jest hybrydą, która dziedziczy koszty
obu światów.
Ograniczenia poszczególnych rozwiązań, które zweryfikowaliśmy podczas
researchu:
- **Strapi** — historia wersji treści nie istnieje w darmowym self-hosted
(tylko płatne plany Growth/Enterprise). Wymaga stale działającego Node +
Postgresa i regularnych aktualizacji.
- **WordPress** — największy ekosystem, ale i największa historia podatności
(głównie pluginy); publiczny panel logowania i PHP do ciągłego patchowania.
- **Grav** (PHP, flat-file — „lekka" alternatywa) — poważne podatności RCE
w ostatnich latach; nadal wymaga serwera PHP wystawionego do internetu.
- **TinaCMS** — edytuje Markdown, ale wymaga backendu: chmura Tina jest
darmowa tylko do 2 użytkowników, a self-hosting to własny serwer Node +
baza (Mongo/Postgres) + auth — wracamy do utrzymywania aplikacji.
- **Ryzyko open-core**: funkcje potrafią z czasem przechodzić do płatnych
planów (przykład wyżej). Gdy treść i jej historia leżą w gicie, nie ma
funkcji, którą dostawca mógłby przenieść do płatnego planu.
## Plusy i minusy obu podejść
Portal ma być utrzymywany przez co najmniej 6 lat, więc bilans trzeba robić
w dwóch horyzontach. Poniżej ocena podejść jako klas rozwiązań, nie
konkretnych produktów.
**Krótkoterminowo (uruchomienie i pierwsze miesiące)**
| | Statyczne + git | CMS z bazą |
|---|---|---|
| Plusy | mało ruchomych części od pierwszego dnia; edytor graficzny gotowy; historia i rollback od razu, w gicie | bogatszy panel od ręki: role i uprawnienia, workflow redakcyjny, relacje między treściami, więcej gotowych integracji |
| Minusy | uprawnienia proste (dziedziczone z gita — bez ról redakcyjnych); przeglądanie historii na razie w interfejsie gita, nie w edytorze | więcej komponentów do postawienia, spięcia i zabezpieczenia od pierwszego dnia (aplikacja, baza, backupy) |
**W horyzoncie 6 lat**
| | Statyczne + git | CMS z bazą |
|---|---|---|
| Plusy | strona publiczna bez aplikacji = brak presji łatek na ścieżce czytelnika; do utrzymania zostaje serwis gitowy (najlepiej ten, który zespół i tak ma); treść w otwartym formacie przetrwa każdą wymianę narzędzi | jeśli z czasem będą potrzebne funkcje aplikacyjne (konta, personalizacja, treści silnie strukturalne), platforma już je ma |
| Minusy | przy bardzo dużej skali (tysiące stron) buildy rosną i wymagają optymalizacji; zaawansowane funkcje redakcyjne zależą od tempa rozwoju narzędzi open-source | kilka dużych migracji wersji w 6 lat (zmiany łamiące); baza wymaga backupów i testów odtwarzania; stała powierzchnia ataku; ryzyko przenoszenia funkcji do płatnych planów |
## „Czy Gitea to nie jest po prostu drugi CMS?"
Uczciwe pytanie: Gitea też ma logowanie, bazę i wymaga aktualizacji
bezpieczeństwa, a dla edytorów musi być dostępna spoza VPN. Czy różnica nie
sprowadza się więc do tego, że zamiast CMS-a utrzymujemy Giteę?
Częściowo tak — i dlatego nie twierdzimy, że utrzymanie jest zerowe. Różnica
polega na trzech rzeczach:
- **Gitea stoi poza ścieżką czytelnika.** Może mieć przerwę, aktualizację,
a nawet zostać przejęta — portal dalej stoi i serwuje bezpieczne pliki.
Najgorszy scenariusz włamania to wandalizm treści: widoczny, z pełną
historią, odwracalny jednym revertem. W CMS-ie serwującym stronę ten sam
incydent oznacza przejętą stronę publiczną.
- **Zespół już utrzymuje Giteę.** Docelowo repozytorium treści może żyć na
istniejącej instancji zespołu — wtedy krańcowy koszt utrzymania jest
bliski zera, a logowanie załatwia jedna integracja z AAI.
- **Klasa oprogramowania.** Gitea to pojedynczy program w Go z SQLite:
aktualizacja to podmiana obrazu i restart, bez ekosystemu pluginów i bez
drzewa zależności npm po stronie serwera. Platformy CMS to frameworki
aplikacyjne z regularnymi migracjami głównych wersji.
## Gdzie jeszcze może się przydać
Ten sam wzorzec — edytor graficzny nad repozytorium Markdown — nie jest
ograniczony do portalu. Naturalni kandydaci u nas:
- **Projekt Mickiewicza** — treści redagowane przez osoby nietechniczne,
a publikowane jako strona statyczna.
- **Dokumentacja Episodes Platform** — już dziś jest w Markdownie; podpięcie
edytora dałoby wygodną edycję w przeglądarce zamiast edytora plików
w Gitei, bez żadnych zmian w istniejącym repozytorium.
Koszt wdrożenia w takich miejscach jest niewielki: edytor to jeden statyczny
plik HTML plus konfiguracja wskazująca repozytorium i strukturę treści.
## Brak lock-inu
Każdy element jest wymienialny osobno, bo treść to czysty Markdown:
- **Sveltia ↔ Decap** — ten sam format konfiguracji; podmiana = jedna linijka
`<script>`.
- **Astro ↔ Hugo / Eleventy** — Markdown zostaje bez zmian, wymieniamy tylko
szablony.
- **Gitea ↔ dowolny hosting gitowy** — GitHub, GitLab i inne.
- Nawet rezygnacja z całego podejścia = eksport trywialny, bo treść od
początku leży w otwartym formacie w naszym repozytorium.
Wniosek z tego demo: zaczynamy od najprostszego rozwiązania, które spełnia
wymagania — graficzny edytor dla redaktorów i bezpieczna, bezobsługowa strona
publiczna. Złożoność dodajemy dopiero wtedy, gdy pojawi się potrzeba, której
to podejście nie obsłuży.
+191
View File
@@ -0,0 +1,191 @@
---
title: "How this portal works: static pages, a visual editor, git as the database"
description: "The architecture behind this demo: a visual editor in the browser, content as Markdown in git, and a public site that is nothing but static files. With an honest comparison against database-backed CMS platforms."
date: 2026-09-11
category: demo
author: Cyfronet
cover: /uploads/diagrams/cover-git-cms.svg
draft: false
---
This portal is a set of **static HTML files** generated from Markdown kept in a
git repository. Editors get a **visual editor in the browser**, and still
**nothing on the public side runs an application or a database**: between the
reader and the content there is only a file server. The one service that does
run, the git server, stands behind the editor and off the reader's path, and we
come back to that honestly below. This article was written and published
through exactly the path it describes.
## The stack in three parts
![The three parts of the stack: Sveltia CMS as the editor, git and Gitea as the database, Astro as the build-time generator, with only nginx and static files involved when a reader opens a page](/uploads/diagrams/stack-overview.svg)
**Sveltia CMS is the editor.** It is one JavaScript file served as a static page
under `/admin/`. It signs the editor in to Gitea and writes Markdown files and
images straight into the repository through the git API. There is no CMS server
and no database behind it, and every save is a commit.
**Git, served by Gitea, is the database.** An article is a Markdown file with a
defined set of fields, and uploaded images sit next to it. History, diffs and a
one-command rollback come from git itself rather than from a paid tier of a
product.
**Astro is a generator, not a server.** Its build turns those Markdown files
into a directory of plain HTML, CSS and images, so deployment is copying that
directory onto a file server. Nothing from Astro runs in production. Pages ship
without JavaScript by default, while components, React among them, are rendered
to HTML during the build, so an interactive dashboard can later be added as an
island on the same site without changing the stack. The build also checks every
article against the defined fields, which means a malformed article stops the
build instead of reaching the public site.
On the reader's side that leaves one moving part: nginx handing over files.
## From a save to a published page
![Five steps of publishing: save in the editor, commit in the repository, change detected, site build, published](/uploads/diagrams/publish-flow.svg)
Publishing is automatic. A save in the editor shows up on the site moments
later, with no manual deployment step in between. Every change is a commit, so
**a full content history and a one-command rollback come for free**.
## How it runs on the machine
![Architecture on the demo machine: the editor writes through Sveltia into the Gitea content repository, a systemd timer runs a one-shot Astro build container, the result lands in the releases volume and nginx serves readers static files only](/uploads/diagrams/architecture-machine.svg)
Two repositories, by design. The portal **code** is developed by the team, the
editorial **content** is written by the CMS. Every build takes the newest commit
from both, overlays content onto code and renders the site, so a push to either
repository republishes. Editors never touch the code repository, and
development never mixes with the editorial history.
Everything runs rootless in podman on a single machine: a Gitea container, an
nginx container, and a one-shot build container started by a systemd timer. A
build that fails changes nothing, because the previous release keeps serving.
For comparison, the same machine running a classic CMS. The diagram keeps the
same skeleton on purpose, so the difference is visible at a glance: every
element is up around the clock, the editor and the reader talk to the very same
application, and its login panel faces the internet.
![Architecture of a database-backed CMS: an application with a public admin panel and on-demand rendering runs non stop, next to a database that needs backups and a separate media volume](/uploads/diagrams/architecture-cms-database.svg)
## Where things are
| What | Where |
|---|---|
| Portal | this site |
| Content editor | `/admin/`, the "Content editor" link in the footer |
| Content repository | `ctao/content` on the demo machine's Gitea, written by the CMS |
| Code repository | `ctao/portal`, maintained by the team |
| Deployment documentation | `deploy/README.md` in the code repository |
## Why a static site
![Attack surface compared: a database-backed CMS exposes an application, a login panel, a database and plugins, while this solution exposes static HTML files only and keeps editing behind a git sign-in](/uploads/diagrams/attack-surface.svg)
- **Security.** What faces the internet is a file server and a directory of
files. There is no admin panel to attack, no database to exfiltrate and no
application runtime carrying its own vulnerabilities.
- **Maintenance.** There is no application that has to be monitored and upgraded
under patch pressure. What remains is a git service, which the team runs
anyway, and a short build script.
- **Speed.** Static HTML is as fast as a page gets, which search engines reward
as well.
- **History.** Versioning is a property of git, not a feature tier of a product.
## Two classes of solution
The dividing line is often misread. The question is not whether content sits in
a database or in files. It is **whether a running application stands between the
reader and the content**.
| | Static + git CMS *(this demo)* | CMS that serves the site itself |
|---|---|---|
| Examples | Sveltia, Decap (+ Astro / Hugo / Eleventy) | Strapi, WordPress, Drupal, Grav, TinaCMS |
| Content lives in | Markdown files in git | usually a database; Grav in files, Tina in git |
| In production you run | a file server | an application, usually with a database, non stop |
| Maintenance | a build script plus a git service | patches, upgrades, database backups |
| Change history | git, built in | product-dependent, sometimes paid |
Two clarifications, so the table is not read too simply. **Grav** keeps content
in files with no database at all, yet a PHP application still serves every page,
which puts it in the right-hand column for attack surface and maintenance.
**TinaCMS** keeps content as Markdown in git, but its editor needs a backend
with a database in order to work, so it inherits the costs of both worlds.
Limits of the individual products, verified during our research:
- **Strapi**: content version history does not exist in the free self-hosted
edition (Growth and Enterprise plans only). It needs Node and PostgreSQL
running at all times, plus regular upgrades.
- **WordPress**: the largest ecosystem, and also the longest vulnerability
history, mostly through plugins; a public login panel and PHP to patch
continuously.
- **Grav** (PHP, flat file, the "light" alternative): serious remote code
execution issues in recent years, and still a PHP server facing the internet.
- **TinaCMS**: it edits Markdown, but it requires a backend. The Tina cloud is
free for up to two users, and self-hosting means your own Node server, a
database and authentication, which is an application to maintain again.
- **Open-core risk**: features can move into paid plans over time, as above.
When the content and its history live in git, there is no feature a vendor
can move behind a paywall.
## Trade-offs over six years
The portal is meant to be maintained for at least six years, so the balance has
to be drawn over two horizons. What follows judges the two approaches as classes
of solution, not individual products.
**Short term: launch and the first months**
| | Static + git | CMS with a database |
|---|---|---|
| Strengths | few moving parts from day one; a visual editor ready to use; history and rollback immediately, in git | a richer panel out of the box: roles and permissions, editorial workflow, relations between content types, more ready-made integrations |
| Weaknesses | simple permissions, inherited from git, without editorial roles; browsing history happens in the git interface rather than in the editor | more components to stand up, connect and secure from day one: application, database, backups |
**Over six years**
| | Static + git | CMS with a database |
|---|---|---|
| Strengths | no application on the reader's path, so no patch pressure there; what stays is a git service, ideally the one the team already runs; content in an open format survives any change of tooling | if application features are eventually needed (accounts, personalisation, strongly structured content), the platform already has them |
| Weaknesses | at very large scale (thousands of pages) build times grow and need attention; advanced editorial features depend on the pace of open-source tools | several major version migrations in six years, with breaking changes; the database needs backups and restore drills; a permanent attack surface; features can move into paid tiers |
## "Isn't Gitea just another CMS?"
A fair question. Gitea also has a login, a database and security updates, and it
has to be reachable by editors. Does the difference come down to maintaining
Gitea instead of a CMS?
Partly yes, and we do not claim that maintenance is zero. The difference rests
on three things:
- **Gitea is off the reader's path.** It can be down, mid-upgrade, or even
compromised while the portal keeps serving safe files. The worst case of a
break-in is content vandalism: visible, fully recorded, and undone with a
single revert. In a CMS that serves the site, the same incident means a
compromised public site.
- **The team already runs Gitea.** The content repository can live on the
instance the team maintains anyway, which brings the marginal cost close to
zero and lets one AAI integration handle sign-in.
- **Class of software.** Gitea is a single Go program with SQLite: an upgrade is
swapping an image and restarting, with no plugin ecosystem and no server-side
npm dependency tree. CMS platforms are application frameworks with regular
major-version migrations.
## No lock-in
Every element can be replaced on its own, because the content is plain Markdown:
- **Sveltia to Decap**: the same configuration format, so switching is one
script tag.
- **Astro to Hugo or Eleventy**: the Markdown stays untouched, only templates
change.
- **Gitea to any git hosting**: GitHub, GitLab, or an internal service.
- Even dropping the whole approach is a trivial export, because the content has
been sitting in an open format in our own repository from the start.
The conclusion we draw from this demo: start with the simplest solution that
meets the requirements, which means a visual editor for the editors and a public
site that needs no care. Add complexity only when a need appears that this
approach cannot serve.