diff --git a/documentation/audits/mockups-2026-10-11/COMPARE.md b/documentation/audits/mockups-2026-10-11/COMPARE.md new file mode 100644 index 00000000..99c8da15 --- /dev/null +++ b/documentation/audits/mockups-2026-10-11/COMPARE.md @@ -0,0 +1,91 @@ +# Three directions for the website, side by side + +Built 2026-10-11. **Nothing here is live.** All three are hidden under `/preview/`, carry +`noindex`, are blocked by `robots.txt`, are in no sitemap and are linked from no live page. + +| | address | +|---|---| +| **A — the current redesign** | | +| **M1 — the site is the dashboard** | | +| **M2 — hybrid** | | + +Screenshots: `shots/`. Desktop at 1440 px, phone at 390 px, all from the deployed pages. + +## Measured, same method for all three + +| | A, current preview | M1, dashboard | M2, hybrid | +|---|---:|---:|---:| +| Requests, first load | 12 | **68** | 16 | +| Weight, first load | 270 KB | **1 012 KB** | **150 KB** | +| HTML document alone | 26 KB | **134 KB** | 13 KB | +| Front page height, 1440 px | 6 385 px | **1 660 px** | 1 853 px | +| Front page height, 390 px | 10 145 px | 6 563 px | **3 057 px** | +| Third-party hosts | 0 | 0 | 0 | +| Horizontal overflow at 390 px | none | none | none | + +M1's catalogue page (`alkalmazasok.html`) is **26 410 px tall on a phone** — 58 cards in one column. +That is its worst measured number and it is not easily fixable while the page's job is "show the +whole catalogue". + +## M1 — the site is the dashboard + +**What it does well.** A visitor sees the actual product in the first second, with 58 real apps, real +logos, real Hungarian taglines and a real screenshot behind every tile. Nothing on the page is a +promise about the product; the page *is* the product. It also makes the apps page genuinely useful +rather than a wall of names: every tile opens what that app does for a family and how to start it. + +**What can go wrong.** A non-technical visitor can read a full-screen dashboard as *somebody else's +account* and look for a login — the brief's own worry, and I think it is the real risk. The welcome +card is the only thing saying "this is a demonstration, look around", and one card is thin defence. +The second risk is weight: **1 MB and 68 requests** on a site that compresses nothing (R-931), four +times the current preview, because the front page is 58 logos. The third is SEO: the front page's +text is a welcome card and 58 app names; the sentences Google currently ranks would have to live +somewhere else. + +**What it would cost to finish.** The largest of the three. Six pages exist as studies and all six +need real design passes; the English twin set does not exist at all and this is the layout where +twinning is most work (every app panel doubles). The catalogue page needs a different phone answer. +The shared-design mechanism in `SHARED-DESIGN.md` §3(a) stops being optional. Call it several +sessions, and it changes what the website *is*, so the SEO baseline needs deliberate re-planning +rather than preservation. + +## M2 — hybrid + +**What it does well.** It is the lightest of the three by a clear margin — **150 KB over 16 +requests**, and the shortest phone page at 3 057 px — while still showing the real dashboard in the +first screen, inside a window frame that reads unmistakably as "a picture of an application" rather +than "you are logged in". It keeps the website's own voice and structure, so the SEO work already +done survives, and it needs no new twin pattern. + +**What can go wrong.** The window is a smaller promise than M1's: four tiles, not the real thing, so +it shows the product without quite letting a visitor *use* it. It is also the least distinctive of +the three — a hero beside a product shot is a normal landing page, which is exactly the charge the +current home page was redesigned to escape. And the window risks reading as a static image unless +the "click a tile" invitation is obvious. + +**What it would cost to finish.** The smallest. It is one page plus its English twin, built out of +components that now exist, and it can borrow the current preview's lower sections nearly as they are. +One session, maybe two with the twin. + +## A — the current redesign, for reference + +Already written up in `audits/redesign-2026-10-10/`. It is the safest of the three, keeps every SEO +string, and is the only one with its "Ki áll mögötte" question already settled. Its weakness is the +one that started this: it still reads as *a website about a product* rather than the product. + +## What I would say if asked + +**M2 is the better bet, and M1 is the better idea.** M2 costs least, risks least, and keeps +everything already decided. M1 is the only one of the three that answers the original complaint +completely — but it is a different website, with a different SEO story, four times the weight, and a +real chance a visitor mistakes it for a login page. + +If the appeal of M1 is "show the real thing immediately", **M2 already delivers most of that for a +fifth of the cost**, and the honest way to find out whether M1's risk is real is to put M1 in front +of two or three people who are not Viktor and watch whether they look for a password field. + +## The register + +Nothing here is filed yet. If a direction is chosen, the work to build it becomes rows; if M1 is +rejected, `website/preview/m1/`, `website/preview/m2/`, `website/preview/mockup.css` and the +`MOCKUPS` set in `scripts/site_gates.py` are deleted together. diff --git a/documentation/audits/mockups-2026-10-11/SHARED-DESIGN.md b/documentation/audits/mockups-2026-10-11/SHARED-DESIGN.md new file mode 100644 index 00000000..c54c72b9 --- /dev/null +++ b/documentation/audits/mockups-2026-10-11/SHARED-DESIGN.md @@ -0,0 +1,128 @@ +# Could the website and the controller share one design? — measured, then answered + +**Report only. Nothing in this document was built.** Written 2026-10-11 while building the M1/M2 +mockups, which is the only reason the numbers below are measurements rather than estimates. + +Baselines: `felhom.eu` `0c86e698b0`, `felhom-controller` `dcd89364a4` (**read only**), +`app-catalog-felhom.eu` `8ea72aa`. + +--- + +## 1. What M1 actually reused + +`website/preview/mockup.css` is deliberately three labelled blocks so this could be counted: + +| Block | Rules | Size | What it is | +|---|---:|---:|---| +| 1. BASE, **adapted** | 8 | 2.5 KB | The controller's reset, tokens and `@font-face`, with the font URLs repointed `/static/fonts/` → `/assets/fonts/` | +| 2. CONTROLLER, **verbatim** | **188** | 19.4 KB | Copied unchanged out of `style.css` | +| 3. MOCKUP-ONLY, **new** | 64 | 7.2 KB | What neither product has an answer for | +| **Total** | **260** | **29.1 KB** | | + +So of the 260 rules M1 needs, **188 (72%) are an unchanged copy** and only **64 (25%) are new**. +The controller's stylesheet has **826 rules**; M1 needed 188 of them, or **23%**. The rest is +storage, deploy wizards, monitoring, restore flows — surfaces a marketing site has no use for. + +**The 18 design tokens are already identical.** Verified this session by parsing both `:root` +blocks: 18 names in each, **zero differing values, none missing on either side**. The brief said so +and it is true. + +What the 64 new rules are actually for: the welcome card, the `minta` badge, the disabled-menu-item +treatment, the `:target` app panel, and M2's browser-window frame. Every one of them exists because +a *website* needs something a *dashboard* does not — none is a restyling of a controller component. + +**Honest caveat on the 188.** Only **129 of the 186** class rules shipped (69%) match a class the +mockup markup actually uses; 57 came along because my extractor matched on selector prefix. A +hand-curated copy would be smaller. The 72% reuse figure is about *how much fits*, not about how +tight the file is. + +## 2. The finding that matters more than the percentage + +**A component-level copy silently drops the element-level rules those components depend on.** + +The extractor keys on class names. It copied every `.sidebar`, `.content`, `.mobile-topbar` and +`.nav-burger` rule, including the whole `@media(max-width: 768px)` block — and silently missed this: + +```css +@media (max-width: 768px) { body { flex-direction: column; } } +``` + +One bare element rule. Without it, measured at 390 px: the sticky mobile topbar stayed a **row** +flex item, pushed `.content` 135 px to the right, collapsed the launcher grid to **one column**, made +the front page **15 597 px** tall on a phone, and gave two pages a `scrollWidth` of 467 in a 375 px +viewport. Everything *looked* copied. Nothing said it was incomplete. + +A second instance in the same build: the controller's off-canvas drawer is gated on a `js` class that +`layout.html` sets in an inline head script. The CSS was all there; the hook was not, so the drawer +never engaged. + +**Both failures are invisible to a diff and invisible to review.** They are the argument for a +mechanism over a convention, and they are why I would not recommend "copy the components when you +need them" as the long-term answer. + +## 3. The two mechanisms, with cost and risk + +### (a) One `felhom-ui.css`, owned in `documentation/design/`, copied into both repos, with a gate + +The pattern this project already uses for things that must stay identical in two places. + +- **Cost.** Write the shared file once by pulling the common components out of both stylesheets + (realistically a day, because the two have drifted in ways nobody has catalogued). Then a gate in + each repo comparing its copy to the canonical one — the same shape as the existing copy-drift + gates, so roughly an afternoon including its decoy. +- **Risk.** Low and *visible*. A drift turns a gate red on the next push, naming the file. The + failure mode is an annoying red gate, not a silently broken phone layout. +- **What it does not solve.** Someone still has to decide what belongs in the shared file. Put too + little in and §2 happens again; put too much in and a controller-only change starts failing the + website's gate for no reason. + +### (b) Serve the controller's `style.css` to the website as the source + +- **Cost.** Near zero to start: one build step copying the file in. +- **Risk.** High, and the risks are the interesting ones: + - **It inverts ownership.** The marketing site's appearance becomes a side effect of a controller + release. A controller change made for a deploy wizard can alter the home page of the public site + without anyone intending it, between two releases nobody reviewed for that. + - **Weight.** The controller's stylesheet is **826 rules**; the website would carry all of them to + use 23%. On a site that currently serves **nothing compressed at all** (R-931), that is a real + cost on every page, not a theoretical one. + - **Different release cadences.** The controller ships several times a day; the website is + git-synced from `main` in a minute. They would be coupled at the speed of the faster one. + +### Which I would pick + +**(a), and not yet.** + +(a) is right in shape: a canonical file plus a gate is the only one of the two where a divergence +*announces itself*, and §2 is a measured demonstration that divergence does not announce itself +otherwise. + +But I would **not build it until the operator has chosen a direction**, because the question (a) +answers only exists if the website keeps wearing the dashboard's clothes. If M1 is rejected, the +website needs about a dozen shared atoms (button, tag, card, alert) and a shared stylesheet would be +a mechanism built for a problem that went away. If M1 is chosen, (a) stops being an improvement and +becomes **necessary** — at that point the website *is* a second renderer of the controller's design, +and keeping two hand-synced copies of 188 rules is exactly the arrangement that produced §2. + +**A third option worth naming, which I would pick over (b):** keep the tokens shared (they already +are, and they are the half that never drifts) and let the components diverge on purpose. That is +today's arrangement, and it has cost nothing so far — because until this week nothing tried to show +the same component in both places. + +## 4. What breaks if the controller's look changes + +Under (a) or (b), the website follows the controller automatically. That cuts both ways: + +- **Good.** A customer who sees the website and then their own box sees one product. Today they see + two designs that merely share colours. That is the whole case for M1. +- **Bad, and specific.** The controller's UI is driven by what a *household operating a box* needs, + and it changes for operational reasons several times a day. A denser `.launch-cell` for boxes with + 40 apps would silently re-flow the public front page. A new state colour added for a restore + wizard would appear in the website's palette. A controller release that narrows the sidebar + changes the public site's navigation width. +- **The asymmetry to be explicit about:** the controller has a known audience of a handful of test + households and can be changed freely. The website is the public face and carries SEO and + first-impression weight. Coupling them means the *low-stakes* surface sets the pace for the + *high-stakes* one. Any shared-design mechanism needs a rule for that, and the simplest is that the + shared file holds only components both surfaces actually render — which is the discipline (a) + enforces and (b) does not. diff --git a/documentation/audits/mockups-2026-10-11/shots/m1-1440-app-panel.png b/documentation/audits/mockups-2026-10-11/shots/m1-1440-app-panel.png new file mode 100644 index 00000000..29cde115 Binary files /dev/null and b/documentation/audits/mockups-2026-10-11/shots/m1-1440-app-panel.png differ diff --git a/documentation/audits/mockups-2026-10-11/shots/m1-1440-inditopult.png b/documentation/audits/mockups-2026-10-11/shots/m1-1440-inditopult.png new file mode 100644 index 00000000..dcec0849 Binary files /dev/null and b/documentation/audits/mockups-2026-10-11/shots/m1-1440-inditopult.png differ diff --git a/documentation/audits/mockups-2026-10-11/shots/m1-390-inditopult.png b/documentation/audits/mockups-2026-10-11/shots/m1-390-inditopult.png new file mode 100644 index 00000000..ae97a5aa Binary files /dev/null and b/documentation/audits/mockups-2026-10-11/shots/m1-390-inditopult.png differ diff --git a/documentation/audits/mockups-2026-10-11/shots/m2-1440-hero.png b/documentation/audits/mockups-2026-10-11/shots/m2-1440-hero.png new file mode 100644 index 00000000..a1c7b685 Binary files /dev/null and b/documentation/audits/mockups-2026-10-11/shots/m2-1440-hero.png differ diff --git a/documentation/audits/mockups-2026-10-11/shots/m2-390-hero.png b/documentation/audits/mockups-2026-10-11/shots/m2-390-hero.png new file mode 100644 index 00000000..7cca38dc Binary files /dev/null and b/documentation/audits/mockups-2026-10-11/shots/m2-390-hero.png differ diff --git a/documentation/audits/mockups-2026-10-11/shots/preview-1440-hero.png b/documentation/audits/mockups-2026-10-11/shots/preview-1440-hero.png new file mode 100644 index 00000000..4f26e2e3 Binary files /dev/null and b/documentation/audits/mockups-2026-10-11/shots/preview-1440-hero.png differ diff --git a/documentation/audits/mockups-2026-10-11/shots/preview-390-hero.png b/documentation/audits/mockups-2026-10-11/shots/preview-390-hero.png new file mode 100644 index 00000000..fc9f0844 Binary files /dev/null and b/documentation/audits/mockups-2026-10-11/shots/preview-390-hero.png differ diff --git a/documentation/backlog/CLOSED-ITEMS.md b/documentation/backlog/CLOSED-ITEMS.md index 1fbc269b..d476c6bf 100644 --- a/documentation/backlog/CLOSED-ITEMS.md +++ b/documentation/backlog/CLOSED-ITEMS.md @@ -53,6 +53,7 @@ The full text of the row below: `git show 625d38645c:documentation/backlog/OPEN- | Row | What | Closed | Evidence | |---|---|---|---| | **R-927** | **Monica was checked against the new-app checklist and STOPPED at 0.2 — upstream has not released anything in 17 months.** (P4) | CLOSED 2026-10-10 — **the operator ruled: keep it out.** The measurements that decided it: no release of any kind since 2025-04-21 and that one a prerelease; no stable release since v4.1.2 on 2024-05-04; the `4.x` branch its README calls "the stable and current version" untouched since 2024-05-04; a 13-month hole in the commit history ended by two commits that add a login-page notice saying the hosted instance and all its data will be deleted at the end of December 2026 "ahead of the new Monica version"; 790 issues open. Nothing in the catalog covers a family address book either way, and Radicale already carries contacts to a phone over CardDAV. **Reasoning kept:** an app is not added because a gap exists — it is added because the app can be kept. Look again when the rewrite ships. | `audits/new-apps-2026-10-10/FIT.md`; the operator's decision 2026-10-10 | +| **R-929** | **The app count disagrees with itself in three places: website prose 58, apps page 59 cards, catalog 60 templates.** (P4) | CLOSED 2026-10-11 — **NOT A DEFECT. The three numbers count three different things, and all three are correct.** MEASURED by reading every `.felhom.yml` in `app-catalog-felhom.eu` `8ea72aa`: **60** template directories, of which `plant-it` is `lifecycle: abandoned` and `wger` is `lifecycle: hidden`, so the controller offers **58** for a new install — exactly what the site's prose says. The page's **59th** card is **FileBrowser**, which carries the page's single „Beépített" badge because it is a built-in, not a catalog app. Set difference both ways: nothing offered is missing from the page, and nothing on the page is unaccounted for. **The premise was wrong on both halves** — no card is uncounted and no template is missing. **Rule kept:** before filing a count disagreement, check whether the counts are counting the same set. | `audits/mockups-2026-10-11/` (the catalog read that measured it); `scripts/catalog.py` output in that session's transcript | | **R-915** | **The Meta app `felhom.eu` was in development mode, so anything it posted was visible only to people with a role on the app.** (P4) | CLOSED 2026-10-09 — the app is **Published**. What it had been waiting for was R-813's Terms of Service URL, which did not exist until the closed-test legal set went live that morning. Filled in Basic settings: **Privacy policy URL** `https://felhom.eu/adatkezeles`, **Terms of Service URL** `https://felhom.eu/feltetelek`, **User data deletion → Data deletion instructions URL** `https://felhom.eu/adatkezeles` (the notice says how: write to `info@felhom.eu`), **Category** „Vállalkozások és oldalak". Meta then reported **„All required app settings are complete"** — the app **icon turned out NOT to be required**, which is worth recording because the original row listed it among the blockers. **Read back from a full page reload, not from the success toast** (Meta's toasts have lied on this Page before): the sidebar badge reads `Published`, the string `Unpublished` is gone, and the page now offers `Unpublish`. No permission was added and no use case changed — `business_management` et al. stay „Ready for testing", which is all a system user needs for the business's own Page. | `audits/facebook-page-details-2026-10-09/E1-meta-app-published.jpg` | **Reasoning kept.** Going Live is about *who can see what the app posts*, not about new powers: the system user already had the Page scopes, and nothing was granted here. The app icon, display name and contact e-mail were listed as Live blockers in the original row; only the two URLs and the category actually were. diff --git a/documentation/backlog/OPEN-ITEMS.md b/documentation/backlog/OPEN-ITEMS.md index 29718164..ea451f59 100644 --- a/documentation/backlog/OPEN-ITEMS.md +++ b/documentation/backlog/OPEN-ITEMS.md @@ -135,7 +135,7 @@ stopping line that lies. | **R-770** | Apps & catalog | P4 | **[P3-LOW] Invidious — fit check only; the recommendation is not to build it.** READ 2026-10-01: playback needs `invidious-companion` (rolling `latest`, no version tags); PostgreSQL 14 (EOL 2026-11); `registration_enabled: true` by default; upstream: a bot check means „your IP is blocked from YouTube”, a 429 can last 24 h, triggered by „someone on your network” — on our boxes that IP is the household's. One bad period in 2026 (March, ~2 weeks). No report found of a family's other devices being bot-checked (inference). **Needs:** the operator's go / no-go. `audits/new-apps-2026-10-01/FIT.md` | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator** **Re-ranked 2026-10-03: P3→P4: a new-app idea waiting on a decision.** | — | — | operator | | **R-771** | Apps & catalog | P4 | **[P3-LOW] moonlight-web — fit check only; not buildable through an HTTP-only tunnel at usable latency.** READ 2026-10-01: two unrelated projects (MrCreativ3001/moonlight-web-stream, the original; linckosz/moonlight-web); both need Sunshine/Apollo/Wolf on a gaming PC on the LAN and WebRTC over UDP (40000-40100/udp; linckosz recommends host networking and sends telemetry by default); both have a WebSocket fallback (high latency, all video through the tunnel); a logged-in user controls the PC's desktop. **Needs:** the operator's go / no-go (LAN-only use would need a different publishing model). `audits/new-apps-2026-10-01/FIT.md` | **WAITING-ON-OPERATOR — rank P3-LOW; owner: operator** **Re-ranked 2026-10-03: P3→P4: a new-app idea waiting on a decision.** | — | — | operator | | **R-905** | Apps & catalog | P4 | **wger's collected style files (283 MB) go into every wger backup, though the app rebuilds them at every start.** Since R-762's fix (`DJANGO_DEBUG=False` + `collectstatic`, catalog `cf1ed43`) the static files sit in a named volume that the backup legs copy like data (measured 283 MB, `audits/design-build-2026-10-06/`); `collectstatic` regenerates them, so they are rebuildable bytes in every Tier-1 unit, Tier-2 copy and off-site snapshot. wger is `lifecycle: hidden` and no box runs it (hub read 2026-10-08). Options to weigh: a non-backed-up volume class for regenerable data, or an anonymous volume. Found by the R-762 helpers 2026-10-08. | **OPEN — needs a design before wger is shown** | — | Design the „regenerable volume" exclusion (catalog + controller backup legs) | CC | -| **R-929** | Apps & catalog | P4 | **The app count disagrees with itself in three places: the website's prose says 58, the apps page renders 59 cards, the catalog holds 60 template directories.** FOUND 2026-10-10 while writing the Facebook campaign, which had to quote a number. `site_gates.py` gate 15 prints „apps pages agree: 59 cards, 59 logos” (it compares the two language sets to EACH OTHER, so it cannot catch a count that is wrong on BOTH); the prose says 58 in 15 places per language set (`website/CHANGELOG.md` 2026-10-10 moved it 56→58 for Grocy + LubeLogger); `find templates -name .felhom.yml` in `app-catalog-felhom.eu` returns 60. So at least one card is not counted by the prose, and at least one template is not on the page — and the gate that looks at app counts is blind to both, because nothing compares the page to the CATALOG. **The campaign post says 58**, matching every prose claim on the site today; if 58 is wrong, a published post is wrong with it. **Fix shape:** reconcile the three (which templates are deliberately not shown — `lifecycle: hidden`, not installable — and which are missing from the page), then make the gate assert the page's card count against the catalog's shown-template count rather than against the other language. Needs the `felhom-app-catalog` skill's exclusion rules. | **OPEN — filed 2026-10-10 by the tester-recruitment session, which did NOT fix it (outside its brief)** | — | Reconcile page cards vs catalog templates vs the prose number; then point gate 15 at the catalog | CC | +| **R-932** | Apps & catalog | P4 | **Eight catalog strings carry an em dash, and they are shown to customers in the controller's own app page.** MEASURED 2026-10-11 while reading every `.felhom.yml` for the website mockups: 8 strings across 5 apps (`recipe-importer` 4, `romm` 1, `calibre-web` 1, `paperless-ngx` 1, `vaultwarden` 1) contain `—` in a `tagline`, `use_case` or `first_step`. These render in the controller's app-info page on every real box, and they will render on any website page that shows catalog copy — the mockups are the first thing to surface them. The house rule (`skills/felhom-web-design` §4) bans the em dash in customer-facing Hungarian and uses the spaced en dash as the gondolatjel; most of these want a colon or a full stop instead, so it is a per-sentence edit, not a find-and-replace. Small, but it lives in a repo this session did not have in scope. | **OPEN** — filed 2026-10-11 by the mockup session | — | edit the 8 strings in `app-catalog-felhom.eu`, one sentence at a time | CC | ## App updates — 4 rows (P3 4)