Eksport strony do ZIP: struktura paczki, format treści i praca z lokalnym LLM
Jak powstaje kopia statyczna witryny, co dokładnie znajduje się w paczce (html/, content/, site.json), jakie są limity i jak użyć eksportu z własnym modelem językowym albo do przeniesienia strony.
Jak powstaje paczka
Eksport nie ma osobnego generatora HTML. Każda podstrona jest renderowana przez ten sam potok, który obsługuje ruch z internetu (szablon, skórka, moduł sklepu, wersje językowe, cache sekcji), więc kopia wygląda dokładnie tak jak żywa strona. Zadanie wykonuje się w kolejce; po zakończeniu właściciel dostaje e-mail z linkiem, a w panelu pojawia się przycisk pobierania.
Lista adresów do zrzutu pochodzi z tych samych źródeł co sitemap.xml: opublikowane podstrony we wszystkich włączonych językach, polityka prywatności każdej wersji językowej oraz adresy modułu sklepu (listingi kategorii, produkty). Szkice i strony zaplanowane na później są pomijane.
Żądania eksportu przedstawiają się agentem KompasfirmExportBot/1.0 i nie przechodzą przez warstwę rejestracji ruchu, więc nie zaśmiecają Kompas Lead Analytics.
Struktura paczki
README.md
site.json
content/
index.md
o-nas.md
uslugi/hydraulika.md
de/index.md
de/ueber-uns.md
html/
index.html
o-nas/index.html
uslugi/hydraulika/index.html
de/index.html
tenant/site.css, tenant/fonts/…, tenant/klaro/…
storage/… (media)
icon.svg, icon.ico, apple-touch-icon.png, site.webmanifest
llms.txt, sitemap.xml, robots.txt
Reguły nazewnictwa: strona główna to index.html, każda inna podstrona to katalog ze swoim index.html (dzięki temu adres /o-nas działa na każdym hostingu statycznym jako /o-nas/). Wersje językowe zachowują prefiks /{lang} z żywej strony. Pliki Markdown mają tę samą hierarchię, ale bez katalogu na końcu (o-nas.md).
Co dzieje się z odnośnikami
W HTML przepisywane są atrybuty href, src, srcset, poster, action, data-src oraz url() w stylach:
| Odnośnik | Co się dzieje |
|---|---|
wewnętrzna podstrona (/o-nas) |
ścieżka względna do pliku w paczce (../o-nas/index.html) |
plik statyczny (/storage/…, /tenant/…, /img/…) |
kopiowany do paczki, odnośnik względny |
plik generowany (/icon.svg, /site.webmanifest) |
pobrany z żywej strony i zapisany w paczce |
adres dynamiczny (/__lead, /szukaj, /_k/e) |
absolutny adres żywej strony |
canonical, hreflang, og:url |
bez zmian, wskazują żywą stronę |
| adresy zewnętrzne | bez zmian |
Skrypt analityki (tenant/track.js) jest usuwany z dokumentów. Katalog tenant/ (style, czcionki, skrypty kalkulatorów i baner zgód) jest kopiowany w całości, bo CSS odwołuje się do czcionek względnie.
Konsekwencja praktyczna: formularz kontaktowy w kopii nadal wysyła zgłoszenie do skrzynki leadów na KOMPASFIRM, dopóki oryginalna strona jest aktywna. Koszyk, zamówienia, popupy i testy A/B w kopii nie działają.
Format content/*.md
Każdy plik zaczyna się nagłówkiem YAML:
---
title: "Hydraulik Szczecin · Aquafix"
description: "Awarie i naprawy z dojazdem w 60 minut."
url: "https://aquafix.kompasfirm.pl/uslugi/hydraulika"
language: "pl"
---
# Hydraulika bez czekania
Przyjeżdżamy w ciągu godziny…
Treść pochodzi z elementu <main> wyrenderowanej strony: nagłówki, akapity, listy, odnośniki, obrazy (), tabele i cytaty. Menu, stopka, formularze, skrypty, ikony SVG i elementy aria-hidden są pomijane. Odnośniki względne są zamieniane na absolutne adresy żywej strony, żeby plik miał sens także wyjęty z paczki.
Format site.json
{
"generator": "kompasfirm",
"format": "site-export/1",
"exported_at": "2026-09-02T10:15:00+02:00",
"website": { "id": 12, "name": "Aquafix", "url": "https://aquafix.kompasfirm.pl",
"template": "business", "template_family": "leadgen",
"default_language": "pl", "languages": ["pl", "de"], "theme": { … } },
"business": { "name": "…", "phone": "…", "address": "…", "hours": "…" },
"business_i18n": { "de": { … } },
"menu": { "pl": [ … ] },
"nav": { "nav": [ … ], "nav_footer": [ … ] },
"pages": [
{ "id": 101, "slug": "home", "language": "pl", "translation_key": "…", "type": "home",
"title": "…", "meta_title": "…", "meta_description": "…", "parent_id": null,
"sections": [ { "type": "hero", "label": null, "hidden": false, "data": { … } } ] }
],
"files": [ { "path": "/", "html": "html/index.html", "markdown": "content/index.md" } ]
}
Sekcje są znormalizowane tak samo jak w narzędziu MCP get_page (stare nazwy pól przepisane na aktualne), więc dane z site.json można bez tłumaczenia podać do update_section, add_section i update_page. To zamyka pętlę: eksport, edycja poza platformą (człowiek albo model), import zmian przez MCP.
site.json nie jest dokumentem import_site: ten kontrakt dotyczy tylko stron budowanych z JSON (EXPOTPL) i opisuje stronę „od zera", a eksport opisuje stronę istniejącą, z identyfikatorami.
Praca z lokalnym modelem językowym
Katalog content/ to najlepsze wejście dla modelu: sama treść, bez klas CSS i skryptów, kilkanaście razy mniej tokenów niż HTML. Przykład z Ollama i modelem uruchomionym lokalnie:
unzip aquafix-2026-09-02.zip -d aquafix
cat aquafix/content/*.md aquafix/content/**/*.md > aquafix/tresc.md
ollama run llama3.1 "Poniżej treść strony firmowej. Oceń każdą podstronę pod kątem \
jasności oferty i wezwania do działania, wypisz 10 konkretnych poprawek. \
$(cat aquafix/tresc.md)"
Sprawdzone zadania: audyt treści i nagłówków, przepisanie opisów usług pod konkretne miasto, wygenerowanie FAQ z istniejących opisów, tłumaczenie robocze pod nową wersję językową, propozycje wpisów na bloga na bazie oferty. Wyniki wklejasz do edytora sekcji albo (w planach z dostępem MCP) zapisujesz przez update_section, podając website_id i page_id z site.json.
Przez API: narzędzia MCP (Scale)
Plany z flagą api_access (Scale i wyżej) robią to samo bez klikania, przez serwer MCP. Dwa narzędzia:
| Narzędzie | Argumenty | Wynik |
|---|---|---|
export_site |
website_id, owner_user_id, wait (bool) |
status eksportu; przy wait=true gotowa paczka i download_url w tym samym wywołaniu |
get_site_export |
website_id, opcjonalnie export_id |
status najnowszego (albo wskazanego) eksportu, liczby, data wygaśnięcia, download_url |
download_url to podpisany link ważny do wygaśnięcia paczki (7 dni), więc pobierze go skrypt, agent albo osoba bez konta w panelu. Ten sam link idzie w mailu z powiadomieniem.
Przykład sesji agenta (Claude, Cursor, dowolny klient MCP):
1. list_websites → website_id = 12
2. export_site {website_id: 12, owner_user_id: 7, wait: true}
→ {status: "done", pages_count: 38, bytes: 41 203 116,
download_url: "https://kompasfirm.pl/pobierz-kopie/91?expires=…&signature=…"}
3. pobierz ZIP, przeczytaj content/*.md, zaproponuj zmiany
4. update_section {website_id: 12, page_id: 101, index: 0, data: {…}}
Przy dużych witrynach (setki podstron, wiele języków) użyj wait=false: export_site zwraca export_id i status pending, a get_site_export odpytuj co kilkanaście sekund, aż zobaczysz done. W trybie samoobsługowym obowiązują te same reguły co w panelu: flaga site_export planu, 30 minut przerwy między eksportami, jedna paczka na stronę. Bez owner_user_id narzędzia działają w trybie administracyjnym, bez bramek planu.
Przeniesienie kopii na inny hosting
Wgraj zawartość katalogu html/ do katalogu głównego hosta (albo do podkatalogu: linki są względne). Nie jest potrzebny PHP ani baza. Na własnym serwerze wystarczy serwować katalog statycznie, np. w nginx:
server {
server_name twojadomena.pl;
root /var/www/aquafix/html;
index index.html;
location / { try_files $uri $uri/ =404; }
}
Pamiętaj o canonical w nagłówkach: kopia wskazuje adres na KOMPASFIRM. Jeśli przenosisz stronę na stałe, podmień te adresy (proste wyszukaj i zamień po domenie) albo przełącz domenę na platformie na nowy host.
Limity i porządek
| Parametr | Wartość |
|---|---|
| dostępność | plan Standard i wyższe (flaga planu site_export) |
| przerwa między eksportami tej samej strony | 30 minut |
| ważność linku do pobrania | 7 dni, potem plik jest usuwany |
| kopie na stronę | jedna (nowa paczka usuwa poprzednią) |
| maksymalnie podstron w paczce | 2000 |
| maksymalnie plików statycznych | 5000 |
| maksymalny rozmiar treści przed kompresją | 600 MB |
| czas zadania | do 15 minut |
Wygasłe i porzucone eksporty sprząta codziennie komenda exports:prune. Dostęp do pobierania mają właściciel witryny i członkowie zespołu; role udostępnienia (redaktor, handlowiec, klient) nie widzą tej funkcji.