website refresh: true numbers (56 apps), claims checked against the capability map, ten missing apps, an English twin of every public page (public, choice B), 404 page; site gates 13-18 + 11 decoys; R-902 opened
gates / gates (push) Failing after 13m1s

Part A: claim table documentation/audits/website-refresh-2026-10-08/claims.md; "100% open source" corrected
from the licence read; unbacked claims cut (firewall, RAID, snapshots, new-machine restore, self-managed
mode, household VPN, "never lost"). Part B: dawarich, docmost, grimmory, homebox, karakeep, mealie, metube,
radicale, recipe-importer, sparkyfitness cards; plant-it and wger cut (not offered). Part C: /en/ twins,
nav language switch, hreflang both ways, sitemap with xhtml:link, og-image-en.png. Part D: site_gates.py
twins/lang/same-apps/no-Hungarian/FAQ-JSON-LD/tail. Operator ruling 9 + choice B in 10-localisation.md §11,
§10.7. Register: R-902 (contact mailer source in no repo); R-813, R-784, R-559 annotated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012qRErfCoiTkvDK9N5XHbzb
This commit is contained in:
2026-10-08 08:29:17 +02:00
parent b119301c6f
commit 67b3fd23d1
115 changed files with 9846 additions and 279 deletions
@@ -0,0 +1,123 @@
// Docmost screenshots for the website card: on scratch guest 9202, headless Chrome through the box's own traefik,
// passing the setup gate as the household. Docmost's own first-run setup creates the invented workspace and its first
// (admin) account; a few INVENTED household pages are added through Docmost's own Markdown import; then its own UI
// is shot. (Docmost 0.96 ships no Hungarian interface; the pages are Hungarian.)
const puppeteer = require('puppeteer');
const fs = require('fs');
const sleep = ms => new Promise(r => setTimeout(r, ms));
const S = JSON.parse(fs.readFileSync('/out/secrets.json'));
const D = process.env.DOMAIN, URL = `https://${process.env.SUB}.${D}`;
const PAGES = [
['Házirend.md', `# Házirend
Közös szabályok, hogy mindenki tudja, mi hol van és mi a teendő.
## Hétköznap
- A mosogatógépet az indítja el, aki utoljára tesz bele.
- A szelektív hulladék kedden és pénteken megy ki.
- Este 10 után csendes pihenő.
## Hétvégén
| Feladat | Ki? |
|---|---|
| Porszívózás | Anna |
| Fűnyírás | Péter |
| Bevásárlás | közösen |
`],
['Wifi és eszközök.md', `# Wifi és eszközök
Vendégeknek a **Vendég** hálózat való, a jelszó a hűtőn van.
## Eszközök
- Nyomtató: a dolgozószobában, hálózaton elérhető
- Okostévé: a nappaliban
- Router: az előszobai szekrényben
> Ha valami nem működik: először újraindítás, utána szólj.
`],
['Nyaralás 2027.md', `# Nyaralás 2027
## Ötletek
1. Balaton, Tihany – kerékpártúra a part mentén
2. Mátra – túrázás, kilátók
3. Őrség – csend, erdő, tökmagolaj
## Csomaglista
- [ ] Személyi igazolványok
- [ ] Naptej
- [ ] Elsősegélycsomag
- [ ] Töltők
`],
['Receptek, amiket szeretünk.md', `# Receptek, amiket szeretünk
- Rakott krumpli – vasárnap
- Gulyásleves – vendégeknek
- Palacsinta – mindig
`],
['Autó karbantartás.md', `# Autó karbantartás
| Mikor | Mi | Megjegyzés |
|---|---|---|
| 2026. március | Olajcsere | 15 000 km |
| 2026. október | Téli gumi | szerviz előre bejelentkezve |
| 2027. január | Műszaki vizsga | |
`],
];
(async () => {
const b = await puppeteer.launch({args: ['--no-sandbox', '--ignore-certificate-errors', '--lang=hu-HU',
'--host-resolver-rules=MAP * ' + process.env.TRAEFIK]});
const p = await b.newPage();
await p.setCookie({name: 'felhom_session', value: S.session, domain: `felhom.${D}`, path: '/', secure: true});
await p.setViewport({width: 1280, height: 800});
await p.goto(URL + '/', {waitUntil: 'networkidle2'});
await sleep(1500);
console.log('landed', p.url().replace(URL, ''));
if (!S.skipseed) {
const r = await p.evaluate(async (S, PAGES) => {
const out = [];
const J = async (u, body) => { const x = await fetch(u, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(body || {})}); return [x.status, await x.text()]; };
const [sc, st] = await J('/api/auth/setup', {name: S.name, email: S.user, password: S.pw, workspaceName: 'Demo Család'});
out.push(['setup', sc, sc >= 300 ? st.slice(0, 160) : '']);
const [lc, lt] = await J('/api/spaces', {page: 1, limit: 20});
const sp = JSON.parse(lt); const items = (sp.data && sp.data.items) || sp.items || [];
out.push(['spaces', lc, items.map(x => x.name).join(',')]);
const spaceId = items[0] && items[0].id;
for (const [fn, md] of PAGES) {
const fd = new FormData();
fd.append('spaceId', spaceId);
fd.append('file', new File([md], fn, {type: 'text/markdown'}));
const x = await fetch('/api/pages/import', {method: 'POST', body: fd});
out.push([fn, x.status, x.status >= 300 ? (await x.text()).slice(0, 120) : '']);
}
return out;
}, S, PAGES);
console.log(JSON.stringify(r));
}
await p.goto(URL + '/home', {waitUntil: 'networkidle2'});
await sleep(3000);
console.log('home', p.url().replace(URL, ''));
if (await p.$('input[type=password]')) { // not signed in by the setup call: Docmost's own sign-in form
await p.type('input[type=email]', S.user);
await p.type('input[type=password]', S.pw);
await p.keyboard.press('Enter');
await p.waitForNavigation({waitUntil: 'networkidle2', timeout: 30000}).catch(() => {});
await sleep(3000);
console.log('after sign-in', p.url().replace(URL, ''));
}
await p.screenshot({path: '/out/1.png'});
await p.click('::-p-text(Házirend)').catch(e => console.log('no page link', e.message));
await sleep(4000);
console.log('shot 2 at', p.url().replace(URL, ''));
await p.screenshot({path: '/out/2.png'});
const pageUrl = p.url();
await p.setViewport({width: 390, height: 844, deviceScaleFactor: 2});
await p.goto(pageUrl, {waitUntil: 'networkidle2'}).catch(() => {});
await sleep(3000);
await p.screenshot({path: '/out/3.png'});
await b.close();
})().catch(e => { console.error(e); process.exit(1); });