Landing page
The root domain shows visitors a landing page about Flowery: Ukrainian at /, English at /en/. It lives in landing/, a static Astro site separate from the shop storefronts, and has no runtime of its own.
How it is served
Section titled “How it is served”npm run landing:build(in the repository root) installslanding/and builds it intopublic/landing(ignored by git), the same way the documentation site builds intopublic/docs.LandingControlleranswers/and/enon the root domain. Visitors get the builtindex.html(no-cache, private, with an ETag, so a repeat visit is a 304). Signed-in users are sent on to their control panel or to onboarding, as/always did: Fortify’shome, sign-in and email verification still land there.- Until the site is built,
/sends visitors to the sign-in page, so a deploy before the build step is harmless. - Its CSS, fonts and images are under
/landing/_astro/and are served by nginx as static files.public/landingis also reachable directly at/landing/; the pages carry canonical andhreflanglinks to/and/en/. config('app.landing_path')(LANDING_PATH) points at the build; tests set it to a temporary folder.
Forge’s deploy script must run npm run landing:build after npm ci (a one-time edit, next to npm run docs:build).
Search engines
Section titled “Search engines”What may be indexed on the root domain is the landing page and the docs; everything else says so itself.
/and/en/carry a canonical link,hreflangalternates (uk,en,x-default), a description, Open Graph and Twitter tags, oneh1, structured data and analton every image./sitemap.xml(SitemapController, root domain only) lists/,/en/with their alternates, and every built docs page with its build date;public/robots.txtallows everything and names it. Submit it once in Google Search Console; after that Google re-reads it on its own.- The homepage proposals (
/homepage-v2… and/en/…) carrynoindex, nofollowand are not in the sitemap. They are not blocked inrobots.txton purpose: a blocked page is never fetched, so itsnoindexis never seen and the address can still be listed from a link. - Every Inertia page (sign-in, registration, onboarding, the control panel) carries
noindex, nofollowfromresources/views/app.blade.php. The storefronts are separate sites on the shops’ hosts and manage their own tags. - The docs site’s canonical links and its own sitemap use
siteindocs/astro.config.mjs; until 26 October 2026 it washttps://flowery.test, so every docs page on production told Google its canonical address was a host that does not exist (#94).
Lighthouse on the production homepage (26 October 2026, mobile)
Section titled “Lighthouse on the production homepage (26 October 2026, mobile)”Re-run with CHROME_PATH="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" npx -y [email protected] https://flowery.com.ua/ --chrome-flags="--headless=new" --output=json --output-path=lh.json and compare with the table.
| Category | Score |
|---|---|
| Performance | 96 (FCP 2.0 s, LCP 2.4 s, TBT 0 ms, CLS 0) |
| Accessibility | 96 |
| Best practices | 96 |
| SEO | 100 |
What it found, and what would raise it:
| Finding | Where | Fix |
|---|---|---|
| Plate captions were 4.05:1 on the plate background (13 px needs 4.5:1) | Plate.astro |
Done: captions use --ink-soft (#94) |
Static assets under /landing/_astro/ are served with max-age=14400: Cloudflare’s default browser TTL, because nginx sends no Cache-Control for them. The file names are content-hashed, so a year is safe. About 245 KiB re-downloaded per repeat visit |
Forge nginx | Add to the site’s nginx config: location ~ ^/(landing|docs)/_astro/ { add_header Cache-Control "public, max-age=31536000, immutable"; } (the docs build hashes its assets the same way). Applied by hand in Forge, like the storefront locations |
| Screenshots are served at their full width on phones (about 83 KiB more than the viewport needs; the phone and pricing plates most of all) | Plate.astro |
Render the plates with Astro’s <Picture> and widths/sizes so a phone gets a narrower file; the AVIF and JPEG sources already exist |
Cloudflare’s analytics beacon (beacon.min.js, /cdn-cgi/rum) is reported as a CSP issue and ships legacy JavaScript |
Cloudflare → Web Analytics | Not the page’s code. Switch the beacon off if Web Analytics is not read; otherwise ignore |
| The largest contentful paint is the lead paragraph, painted after the two preloaded font files | Landing.astro |
Already fast; font-display: swap or optional on the two faces would paint the text before the fonts arrive, at the cost of a swap |
What is on it
Section titled “What is on it”The copy is in landing/src/i18n/uk.ts (the main language) and en.ts, which must stay claim for claim the same. Every claim describes something Flowery does today; there are no reviews, customer counts, prices or delivery promises. When a feature changes, change the page in the same PR, as with any other documentation.
Since 8 October 2026 the page leads with what no competitor shows: stems tracked from the delivery to the bouquet, in dated batches used first-expiring-first-out and reserved when an order is confirmed. The research behind that, the competitors read and the open items are in improvement-plans/Homepage-Research-2026-10.md. In order:
- Hero. Category words for search and for people («Облік, замовлення і сайт для квіткового магазину»), the claim «Від поставки до букета в руках — кожне стебло на обліку», «Створити магазин» and «Як це працює». Below it the product itself: the supply batches with stock, reservations, expiry and freshness, beside the bouquet builder on the website. Phones show only the builder, which reads at phone width.
- How it works. One order in six steps (delivery, bouquet, order, reservation, delivery to the customer, margin), each with the real screen behind it. On phones the steps sit in a row to swipe through, with the next one peeking in, under a thin hairline scrollbar; the row is a tab stop only while it scrolls (
page.tschecks), so desktop keyboard users do not land on a grid that goes nowhere. - Freshness. Batches, which ones to use first, reservations that keep the same stems from two customers on 14 February or 8 March, write-offs, the «Потребує уваги» page, and a ledger that explains every number.
- Website. Catalogue, real availability, the builder, two themes, and how customers receive a bouquet. Online card payment is named as the next stage.
- AI for the catalogue. See below.
- Money. Material cost and margin on every order, the profit and loss statement in Finance down to operating profit, and the team: florists see stems and stock, while cost and Finance are for managers, admins and the owner.
- Getting started. Email or Google, the shop’s name and address, flowers from the ready list and bouquets from ready recipes (or the demo shop), then one click to publish the website and one to turn on pickup orders.
- FAQ and the closing action.
The single primary action everywhere is «Створити магазин»: it says what happens next, where “get started” makes people hesitate.
The AI section describes the AI tools in the catalogue forms (AiContentController) as a bounded job, not as the product’s category:
- bouquet images generated from the bouquet’s own stems and quantities, in five European floristry styles and five settings, with or without a model, in three consistent angles;
- flower and bouquet descriptions in Ukrainian or English;
- what AI does not do: it changes no prices, stock or orders; the image is generated, not a photograph, and can differ from the real bouquet; the shop decides what goes on its website.
The page does not name the AI providers; Settings → AI in the control panel does, and ADR-017 records them.
The example is real output: the three angles Flowery generated for the bouquet «Літній сад» (4 peonies and 2 hydrangeas) on 18 January 2026, shown beside that recipe and tagged «Згенеровано ШІ». The peonies’ shade changes between the angles; the page keeps that, because it is exactly what the “may differ” line warns about. There is no AI that designs bouquets, forecasts demand or runs the shop, and the page does not claim one.
Screenshots
Section titled “Screenshots”Everything that looks like the product is the product: no drawn illustrations. Every screen, or group of screens, carries a line saying it is real and uses demo data («Справжні екрани Flowery на демо-даних»).
- Website (
landing/src/assets/shots/): the demo shop (pilot-shop, temporarily renamed «Квітковий двір» while they were taken) in both languages, with its free-licence demo photos (resources/demo/CREDITS.md). - Control panel (
landing/src/assets/panel/): crops of single cards from the same demo shop in the light theme, in both languages, at 2× scale. To keep them readable some table columns are hidden (batch code, status, unit price, line total), as are the flowers’ colour codes and the totals row; the Uklon card hides the courier’s name and phone. Three demo orders were confirmed first so the batches show real reservations. - AI (
landing/src/assets/ai/): the generated images described above.
To retake them, sign in to the demo shop with php artisan dev:login, choose the light theme and the language (the control panel reads it from localStorage.language), and capture each card at 2× scale. Phone screens of the website are 390 × 844 at 2×.
What it deliberately does not say yet
Section titled “What it deliberately does not say yet”- Prices, a trial or a free plan: billing is not decided (roadmap).
- Online card payment: named as the next stage.
- The cost of wrapping: packaging has no cost yet (ADR-018), so the money section names flowers only. The first version of this page (#74) said wrapping was costed too; #75 corrected it.
- Own domains: the FAQ says yes since 8 October 2026 (ADR-022); until then it said websites run on
name.flowery.com.uaonly. - Fiscal receipts, Nova Poshta, a messenger inbox, an offline mode: not built, and not yet answered on the page.
- Who is behind Flowery and how to reach a person: waiting for the owner’s details (see the research file).
Proposals beside the homepage
Section titled “Proposals beside the homepage”Since 12 October 2026 (#89) a redesign is tried out at its own address before it replaces the homepage: /homepage-v2 (and /en/homepage-v2), /homepage-v3, and so on. They are pages of the same Astro site (landing/src/pages/homepage-vN/), built and deployed with it, served by LandingController::proposal() to visitors and signed-in users alike (the owner compares them while signed in), and marked noindex, nofollow with a canonical of their own address, so search engines keep the homepage. A proposal’s sources live under landing/src/vN/; the homepage’s under landing/src/components/. Promoting a proposal means moving its sources into place and deleting its route page; the route pattern stays for the next one.
The page has had three looks and two more proposals after them; the second look is the homepage, v2, v3 and v4 are proposals at their own addresses.
- The first (5 October 2026) used the stock SaaS kit, and the owner found it looked generated: soft gradients and glows, rounded cards with shadows, pill buttons, check-mark bubbles, a phone mock-up with a floating card, and a sparkle icon.
- The second (5–12 October 2026) was a printed florist’s trade catalogue in the brand kit: ivory paper and ink, hairline rules, Literata headings, Onest text, real screens in soft frames. On 8 October the editorial devices went (numbered section heads, «Рис. N» captions, the stock photograph); on 12 October the tablet widths and crops were polished (#86). The owner’s verdict on the whole: it “can look a bit as AI slop” (the cream-paper-serif register is the look generated pages cluster around).
- The third, v2, the flower auction hall (12 October 2026, #88): chosen by the owner from a dealt hand of directions drawn from the florist’s own world (a bucket tag, the Dutch auction clock, Kyiv’s neon «Квіти» sign, a struck batch, a shelf-life section) against the category standard. It was the homepage for a few hours; on the same day the owner put the catalogue page back at
/and moved v2 to/homepage-v2(#89), asking for a v3 in the same visual world but with a concept from the flower business rather than the auction. The decision record is the surface brief in.impeccable/surfaces/and the system is inDESIGN.md, which describes v2’s world (the vector v3 continues), not the catalogue page at/.
v2: the auction hall
Section titled “v2: the auction hall”The homepage is the Dutch flower-auction hall. Perishability is money on a clock.
- The dial. The first screen is one great dial counting the days a batch has left: a forest ring with a 0–6д scale, a rose arc lit from 0 to where the hand stands, and the claim («Від поставки до букета в руках — кожне стебло на обліку», the last clause in blush) in the dial’s centre over the count («2 дні · лишилося у партії ранункулюса»). On load the hand is wound to the end of the scale and sweeps once to the batch (1.2 s, exponential ease-out); under
prefers-reduced-motion, or without the script, it renders settled. On phones the dial is seen from closer: wider than the screen, cropped at the sides, the claim inside it. - The lot card. Beside the dial, an ivory card with today’s lot: the real ranunculus batch from the demo shop (залишок 90, зарезервовано 55, вільно 35, ціна закупівлі 45,00 грн, придатно до 10/10/2026), the lead paragraph and the buyer’s button «Створити магазин». Every number is the demo shop’s data as captured for the screenshots; the card says so.
- The hall and the sheets. Ink (
#1c1f1b) carries the dial, freshness, AI, getting started and the close; ivory sheets carry what a florist reads closely (how it works, the website, money, FAQ). Rules are 1px ivory at 20–40% on ink, hair on ivory. No gradients, glows or shadows. - Type. Unbounded (wide, Cyrillic-first; weights 600–800) for the claim, numerals, lot names and section titles; Onest for text and controls; tabular figures wherever stems or money appear. Literata left the page with v2; the brand kit’s Literata/Onest pairing still holds for the control panel and emails (brand).
- The lots. “How it works” is a lot list: six numbered lots (Лот 1–6) with the real screen under each; on phones a row to swipe. Freshness shows a small day-dial per demo batch (півонія 1 день … гербера 3 дні) beside the attention page. The AI section’s recipe is a lot card; money is the settlement sheet.
- What stayed. The copy, the screenshots, the honesty rules, both languages, the single primary action, the “real screen on demo data” captions, the phone menu, the language cookie, and the 44 px targets. The category line («Облік, замовлення і сайт для квіткового магазину») is no longer an eyebrow over the headline; it lives in the page title, the description and the footer.
Three widths are checked: phones (one column), tablets from 48rem (pairs side by side with modest gaps) and desktop from 60rem (the dial fills the left, the lot card the right; the wide gaps).
v3: the florist’s day (proposal at /homepage-v3)
Section titled “v3: the florist’s day (proposal at /homepage-v3)”Chosen by the owner on 12 October 2026 (#90) from a dealt hand of page concepts drawn from the flower business (a stock calendar, the florist’s day, the cold-room shelf), keeping v2’s world. One day in the shop is the page’s spine: the six steps of an order are the day’s stations on a forest band, 07:00 the delivery, 08:30 the bouquet, 09:00 the order from the website, 10:00 the reservation, 15:00 the Uklon delivery, 20:00 the margin, each an ivory card with the hour, the step’s text and its real screen, hanging under the band in two staggered rows. A rose «зараз» mark slides along the band to the visitor’s own local time (the script reads the clock; without it the mark stays hidden, so the page never claims a time it does not know). The claim stands over the band with the time card beside it carrying the lead and the action; on phones the stations stack along a vertical forest rail and the time card follows the claim, so the action is in the first screen. The separate «Як це працює» section is gone: the strip is how it works. The rest of the page is v2’s (freshness with the day-dials, the website, AI, money, getting started, FAQ, the close), with the auction’s dial and lot card nowhere on it.
v4: the stock calendar (proposal at /homepage-v4)
Section titled “v4: the stock calendar (proposal at /homepage-v4)”Built on 13 October 2026 (#91) from the first concept of the hand dealt for v3, the one the roll led with, in v2’s world. The first screen is the month on the florist’s wall: the week of 5–11 October 2026 with Thursday the 8th (the day the batch screens were captured) as a forest column marked «сьогодні», and the five demo batches as ivory bars from that day to their use-by day: півонія to the 9th, ранункулюс to the 10th with «55 у резерві» in rose, евкаліпт to the 11th with «17 у резерві», гортензія and гербера to the 11th, each bar ending in a rose cap where the batch dies. Saturday the 10th is circled in blush (the stake on ink), and a note under the grid says why: the ranunculus batch reaches its use-by day with 55 stems already reserved for confirmed orders, which Flowery shows two days ahead. The week after it is drawn with numbers only. On load the bars grow from the 8th to their day, one after another (CSS only; settled under reduced motion). The ivory stock sheet beside the calendar («Склад на тиждень · 5–11 жовтня»: 5 партій, 348 стебел, 72 у резерві, найближчий термін 09/10/2026) carries the lead, «Створити магазин» and «Як це працює». Two departures from the decision sketch keep it honest: the bars start on the snapshot day, not on a delivery day the screens do not show, and no order is placed on a day, because the captured screens name no order’s date. Below tablet width the bars carry only the names and a ruled legend under the grid carries the counts and dates; from tablet width the counts move into the bars and the legend stays for screen readers only; the stock sheet follows. The rest of the page is v2’s, forest board and lot list included.
The homepage today
Section titled “The homepage today”/ serves the catalogue page (the second look above), unchanged from #86: ivory paper and ink, Literata and Onest, the running heads, the real screens in soft frames. Its sources are landing/src/components/, landing/src/styles/global.css and landing/src/scripts/page.ts; the copy in landing/src/i18n/ is shared with the proposals, which add their own keys (the v2 dial and lot card, the v3 day, the v4 calendar) beside it.
The favicons and the app manifest are the brand’s, shared with the control panel.