Hand-rolled login/register/logout on Laravel's built-in Auth facade
rather than Breeze/Jetstream, which scaffold Tailwind v3 config and
would fight our existing Tailwind v4 CSS-first setup. Login/Register
are Livewire components; logout is a plain POST route (auth-gated,
CSRF-protected).
Routing: "/" is now a public landing page describing the project;
the sites list moved from "/" to "/sites" to make room for it.
Data gating: App\Support\GuestPreview::paginate() forces page 1 and a
5-row page size for unauthenticated visitors on Sites, Discover, and
a site's Pages/Backlinks tables, while total() still reflects the
real match count — authenticated users get the existing full
pagination unchanged. A shared guest-preview-notice component shows
"N of M results, sign in to see all" and only renders when something
is actually being hidden.
Testing: pointed the test suite at a dedicated MySQL database
(huginn_testing) instead of the default in-memory SQLite, since the
existing fulltext index migration isn't SQLite-compatible — this app
is MySQL-specific by now regardless. Added AuthFlowTest (register,
login, wrong-password rejection, logout) and GuestPreviewTest (guest
capped to a preview, authenticated sees everything), all passing.
Also fixed a real bug the tests caught: request()->session() isn't
reliably attached during Livewire's in-process test action calls;
switched Login/Register to the session() helper, which resolves the
session store directly and works in both contexts.
The CDX languages field (ISO 639 codes, e.g. "spa,eng") has been
captured on every page since the first ingestion command, but never
surfaced anywhere. Filters via FIND_IN_SET for an exact code match
rather than a LIKE substring match, since the column holds a
comma-separated list.
Verified against real data: lang=spa returns exactly the expected 47
sites (25+22 across two pages), a bogus code renders the empty state,
and lang=spa combined with tld=es correctly narrows to 20.
Filters sites by server/powered_by/generator (e.g. "Shopify",
"WordPress", "nginx"), combinable with the existing keyword/TLD
filters. Results table now also shows each site's detected platform.
Verified: platform=Wix correctly isolates the one known Wix site,
tld=es+platform=nginx narrows to the 12 real nginx-hosted .es sites,
and the no-match case renders the empty state correctly.
The actual "who sells honey with a .es domain" feature: search sites
by keyword — matched against page title/description/keywords/body
text via a new MySQL fulltext index on site_pages — combined with an
optional TLD filter on the domain. Results are sites ranked by number
of matching pages. Shows nothing until a filter is entered, so it
doesn't just duplicate the plain Sites browse page.
Verified against real .es data pulled in for the test (dominio ->
4 matching sites, correctly ranked and TLD-filtered).
Home page is now a Livewire-powered, searchable/paginated Site list
(search by domain) instead of the stock Laravel welcome page. Clicking
a site goes to a plain controller-rendered detail page listing its
pages. Shared layout at resources/views/components/layouts/app.blade.php.